#define CHECK_NumberVec2
using System;

namespace FixedPointMath
{
    [Serializable]
    public struct Vector2
    {
        public Number x;

        public Number y;

        public static Vector2 Zero = new Vector2 { x = Number.Zero, y = Number.Zero };
        public static Vector2 One = new Vector2 { x = Number.N1, y = Number.N1 };

        public Vector2(Number _x, Number _y)
        {
            this.x = _x;
            this.y = _y;
        }

        #region object
        public override bool Equals(object o)
        {
            if (o is Vector2)
            {
                var oth = (Vector2)o;
                return this.x == oth.x && this.y == oth.y;
            }
            return false;
        }
        public override int GetHashCode()
        {
            return (int)(this.x * 23 + this.y);
        }
        #endregion


        #region 基本运算及比较
        public static Vector2 operator +(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x + b.x, a.y + b.y);
        }

        public static Vector2 operator -(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x - b.x, a.y - b.y);
        }

        public static bool operator ==(Vector2 a, Vector2 b)
        {
            return a.x == b.x && a.y == b.y;
        }

        public static bool operator !=(Vector2 a, Vector2 b)
        {
            return a.x != b.x || a.y != b.y;
        }

        public static Vector2 operator -(Vector2 lhs)
        {
            lhs.x = -lhs.x;
            lhs.y = -lhs.y;
            return lhs;
        }

        public static Vector2 operator *(Vector2 lhs, Number rhs)
        {
            lhs.x *= rhs;
            lhs.y *= rhs;
            return lhs;
        }
        #endregion

        #region 常用方法、属性
        /// <summary>
        /// 单位向量
        /// </summary>
        public Vector2 normalized
        {
            get
            {
                Vector2 result = new Vector2(this.x, this.y);
                result.Normalize();
                return result;
            }
        }

        /// <summary>
        /// 单位向量
        /// </summary>
        public void Normalize()
        {
            if (this.x != Number.Zero || this.y != Number.Zero)
            {
                var len = this.magnitude;
                this.x /= len;
                this.y /= len;
            }
        }

        /// <summary>
        /// 限定长度
        /// </summary>
        /// <param name="maxMagnitude"></param>
        public void ClapMagnitude(Number maxMagnitude)
        {
            if (maxMagnitude > Number.Zero)
            {
                var square = this.squareMagnitude;
                if (square > maxMagnitude * maxMagnitude)
                {
                    var len = square.Sqrt();
                    this.x = this.x * len / maxMagnitude;
                    this.y = this.y * len / maxMagnitude;
                }
            }
            else if (maxMagnitude == Number.Zero)
            {
                this.x = Number.Zero;
                this.y = Number.Zero;
            }
        }

        /// <summary>
        /// 根的平方
        /// </summary>
        public Number squareMagnitude
        {
            get
            {
                return this.x * this.x + this.y * this.y;
            }
        }

        /// <summary>
        /// 平方根
        /// </summary>
        public Number magnitude
        {
            get
            {
                return (this.x * this.x + this.y * this.y).Sqrt();
            }
        }

        /// <summary>
        /// 以下标形式处理字段
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Number this[int index]
        {
            get
            {
#if CHECK_NumberVec2
                if (index < 0 || index > 1)
                {
                    throw new Exception("NumberVec2 public Number this[int index] get index invalid");
                }
#endif
                return index == 0 ? this.x : this.y;
            }
            set
            {
#if CHECK_NumberVec2
                if (index < 0 || index > 1)
                {
                    throw new Exception("NumberVec2 public Number this[int index] set index invalid");
                }
#endif
                if (index == 0)
                {
                    this.x = value;
                }
                else if (index == 1)
                {
                    this.y = value;
                }
            }
        }
        #endregion

        #region 废弃
        //private static readonly int[] Rotations = new int[]
        //{
        //1,
        //0,
        //0,
        //1,
        //0,
        //1,
        //-1,
        //0,
        //-1,
        //0,
        //0,
        //-1,
        //0,
        //-1,
        //1,
        //0
        //};

        //public NumberVec2(Number x, Number y)
        //{
        //    this.x = x;
        //    this.y = y;
        //}

        //public static long DetLong(ref VInt2 a, ref VInt2 b)
        //{
        //    return (long)a.x * (long)b.y - (long)a.y * (long)b.x;
        //}

        //public static long DetLong(VInt2 a, VInt2 b)
        //{
        //    return (long)a.x * (long)b.y - (long)a.y * (long)b.x;
        //}

        //public static VInt2 Rotate(VInt2 v, int r)
        //{
        //    r %= 4;
        //    return new VInt2(v.x * VInt2.Rotations[r * 4] + v.y * VInt2.Rotations[r * 4 + 1], v.x * VInt2.Rotations[r * 4 + 2] + v.y * VInt2.Rotations[r * 4 + 3]);
        //}

        #endregion
    }
}
